﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetDon.OA.Data.EntityClasses;
using NetDon.OA.Data.Linq;
using NetDon.OA.Interface;
using NetDon.OA.Interface.Location;
using SD.LLBLGen.Pro.ORMSupportClasses;

namespace NetDon.OA.Business.Location
{
    public class LocationService : ILocationService
    {
        private readonly ProvinceService _provinceService = new ProvinceService();
        private readonly CityService _cityService = new CityService();
        private readonly AreaService _areaService = new AreaService();

        #region Implementation of ILocationService



        public IEnumerable<ProvinceData> GetProvinces()
        {
            return _provinceService.GetProvinces();
        }

        public IEnumerable<CityData> GetCities(string provinceCode)
        {
            return _cityService.GetCities(provinceCode);
        }

        public IEnumerable<AreaData> GetAreas(string cityCode)
        {
            return _areaService.GetAreas(cityCode);
        }

        public AreaData GetArea(string areaCode)
        {
            return _areaService.GetArea(areaCode);
        }

        public ProvinceData GetProvince(string provinceCode)
        {
            return _provinceService.GetProvince(provinceCode);
        }

        public CityData GetCity(string cityCode)
        {
            return _cityService.GetCity(cityCode);
        }

        public ProvinceData GetProvinceByName(string name)
        {
            var metaData = new LinqMetaData();
            var provinceData = (from province in metaData.Province where province.Name ==name.Trim()
                                         select province).FirstOrDefault();
            return new ProvinceData() { Name = provinceData.Name ,ProvinceId = provinceData.ProvinceId};

        }

        public CityData GetCityByName(string city)
        {
            var metaData = new LinqMetaData();
            var cityData = (from province in metaData.City
                                where province.Name == city.Trim()
                                select province).FirstOrDefault();
            return new CityData() { Name = cityData.Name, CityId = cityData.CityId };
        }
        #endregion


    }


    #region Nested type: ProvinceService

    class ProvinceService : PrimitiveCachableService<ProvinceData>
    {
        public ProvinceService()
            : base("Province")
        {
        }

        public IEnumerable<ProvinceData> GetProvinces()
        {
            var list = new List<ProvinceData>(GetAllData());
            list.Sort((x, y) => StringComparer.CurrentCultureIgnoreCase.Compare(x.Name, y.Name));
            return list;
        }

        public ProvinceData GetProvince(string provinceCode)
        {
            return GetData(provinceCode);
        }

        private ProvinceData GetProvinceData(ProvinceEntity province)
        {
            return new ProvinceData
            {
                ProvinceId = province.ProvinceId,
                Name = province.Name
            };
        }

        protected override ProvinceData OnLoadData(object key, ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            List<ProvinceEntity> list = (from province in metaData.Province
                                         where province.ProvinceId == (string)key
                                         select province).ToList();
            return list.Count > 0 ? GetProvinceData(list[0]) : null;
        }

        protected override object GetDataKey(ProvinceData data)
        {
            return data.ProvinceId;
        }

        #region Overrides of PrimitiveCachableService<ProvinceData>

        protected override IEnumerable<ProvinceData> OnLoadAllData(ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            List<ProvinceEntity> list = (from province in metaData.Province
                                         select province).ToList();
            return list.Select(province => GetProvinceData(province));
        }

        #endregion
    }

    #endregion

    #region Nested type: CityService

    class CityService : CategoryCachableService<CityData>
    {
        public CityService()
            : base("City")
        {
        }

        public IEnumerable<CityData> GetCities(string provinceCode)
        {
            var list = new List<CityData>(GetCategoryData(provinceCode));
            list.Sort((x, y) => StringComparer.CurrentCultureIgnoreCase.Compare(x.Name, y.Name));
            return list;
        }

        public CityData GetCity(string cityCode)
        {
            return GetData(cityCode);
        }

        private CityData GetCityData(CityEntity city)
        {
            return new CityData
            {
                CityId = city.CityId,
                ProvinceId = city.ProvinceId, 
                Name = city.Name
            };
        }

        protected override CityData OnLoadData(object key, ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            if (key != null)
            {
                List<CityEntity> list = (from city in metaData.City
                                         where city.CityId == (string)key
                                         select city).ToList();
                return list.Count > 0 ? GetCityData(list[0]) : null;
            }
            return null;
        }

        protected override object GetDataKey(CityData data)
        {
            return data.CityId;
        }

        protected override object GetCategory(CityData data)
        {
            return data.ProvinceId;
        }

        protected override IEnumerable<CityData> OnLoadCategoryData(object category, ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            
            List<CityEntity> list = (from city in metaData.City
                                     where city.ProvinceId == (string)category
                                     select city).ToList();
            return list.Select(city => GetCityData(city));
        }
    }

    #endregion

    #region Nested type: AreaService

    class AreaService : CategoryCachableService<AreaData>
    {
        public AreaService()
            : base("Area")
        {
        }

        public IEnumerable<AreaData> GetAreas(string cityCode)
        {
            var list = new List<AreaData>(GetCategoryData(cityCode));
            list.Sort((x, y) => StringComparer.CurrentCultureIgnoreCase.Compare(x.Name, y.Name));
            return list;
        }

        public AreaData GetArea(string areaCode)
        {
            return GetData(areaCode);
        }

        private AreaData GetAreaData(AreaEntity area)
        {
            return new AreaData
            {
                AreaId = area.AreaId,
                CityId = area.CityId, 
                Name = area.Name
            };
        }

        protected override AreaData OnLoadData(object key, ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            List<AreaEntity> list = (from area in metaData.Area
                                     where area.AreaId == (string)key
                                     select area).ToList();
            return list.Count > 0 ? GetAreaData(list[0]) : null;
        }

        protected override object GetDataKey(AreaData data)
        {
            return data.AreaId;
        }

        protected override object GetCategory(AreaData data)
        {
            return data.CityId;
        }

        protected override IEnumerable<AreaData> OnLoadCategoryData(object category, ITransaction transaction)
        {
            var metaData = new LinqMetaData(transaction);
            List<AreaEntity> list = (from area in metaData.Area
                                     where area.CityId == (string)category
                                     select area).ToList();
            return list.Select(city => GetAreaData(city));
        }
    }

    #endregion
}
